/*
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

#ifndef _READER_H
#define _READER_H

#include <iostream>
#include <fstream>
#include <string>
#include <exception>


//! Rozhraní před lexikální analýzou.
/*!
 * Připravuje vstupní soubor k lexikální analýze. Jejím cílem je, zprostředkovat
 * rozhraní, které pomocí vestavěných bufferů bude vracet vždy jeden znak z vstupního souboru
 * , vracet se zpět minimálně jeden znak zpět, a vracet řetězec z bufferu.
*/
class reader{

	private:
		//! Velikost jedné poloviny bufferu.
		/*!
		* Buffer je rozdělen na dvě poloviny, aby byl schopen plnit kroky vzad a vracet
		* řetězec. Vždy když dojde k přeteční jedné poloviny je naalokována druhá polovina daty
		* a ukazatel aktuálního znaku se přesenu právě na tuto polovinu. Stará polovina slouží 
		* právě pro kroky zpět, nebo pro navrácení požadovaného řetězece.
		*/
		static const int BUFFER_LENGTH = 1024;
	
		//! Vstupní file stream.
		std::istream *inputFile;
		//! Pamět bufferu
		char buffer[BUFFER_LENGTH * 2];
		//! Aktuální pozice.
		/*!
		* Aktuální pozice je reprezentováná absolutním offsetem vstupního souboru.
		* Tento offset se poté modulí, aby mohly být použit pro buffer.
		*/
		long back;
		std::ios_base::iostate exceptionsBitmask;
		bool flag;
		
		void read(char *, unsigned);
		
	public:
		//! Vyjímka při přeteční bufferu.
		/*!
		* Tato vyjímka je hozena vždy, když dojde k překročení bufferu.
		* K překročení bufferu může dojít, když použijeme více kroků zpět, 
		* než jakými disponuje buffer, nebo budeme žádat délku řetězce
		* , jakou buffer nemůže poskytnout.
		*/
		class bufferOverflow: public std::exception{
	
			public:
				virtual const char *what() const throw();

		};
		//! Konstruktor readeru.
		/*!
		* \param file Vstupní stream musí být otevřen v binárním módu.
		*/
		reader(std::istream *);
		~reader();
		
		//! Inicializace readeru.
		/*!
		* Musí být vždy provedena před voláním, funkcí které vracejí jakákoli
		* data z bufferu. Jako např. getChar() ...
		* Při inicializaci může nastat vyjímka spojená s chybou čtení souboru.
		*/
		void initialize() throw(std::ifstream::failure);
		//! Aktualní znak.
		/*!
		* Vrací znak, na který se právě ukazuje. Neposouvá ukazatel a nemění stav
		* objektu.
		*/
		int getCurrentChar() const;
		//! Vrací následující znak.
		/*!
		* Posouvá ukazatel o jeden znak vpřed, a vrací nový znak.
		* Může nastat vyjímka spojená s chybou čtení souboru.
		*/
		int getChar() throw(std::ifstream::failure);
		//! Posouvá ukazatel.
		/*!
		* Posune ukazatel o jeden znak zpět. Může nastat vyjímka
		* spojená s přetečením bufferu.
		*/
		void getBack() throw(bufferOverflow);
		//! Délka aktualně přečtených dat.
		/*!
		* Vrací délku dat, která byl již přečtena. Nepočítají se skoky zpět atd..
		* Délka dat reprezentuje aktuaní pozici.
		*/
		unsigned long getLength() const;
		//! Přečte řetězec.
		/*!
		* Přečte řetězec z bufferu z aktualní pozice - délka řetězce.
		* \param lexem String do kterého se řetězec uloží.
		* \param len Délka řetězce, který se má zapsat. Zapíše se řetězec
		* , který se nachazí o len nalevo od aktualní pozice a končí aktualní
		* pozicí.
		*/
		std::string &getString(std::string &, int) const throw(bufferOverflow);
		
};

#endif
